#pragma once

#include <iostream>
#include <string>
#include <functional>
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "ThreadPool.hpp"
#include "Log.hpp"
#include "Socket.hpp"
#include "InetAddr.hpp"

#include <stdexcept>

using namespace net_work;
const static int default_backlog = 6;
using task_t = std::function<void()>;
using handler_t = std::function<std::string(std::string)>;

class TcpServer {
    public:
        TcpServer(uint16_t port, handler_t handler) 
        :_port(port), _isrunning(false), _listensock(new TcpSocket()), _handler(handler)
        {}
        ~TcpServer() {}

        void Init() {
            _listensock->BuildListenSocketMethod(_port, default_backlog);
        }
    
        // InetAddr addr  便于打印 ip 和 port
        // 仅用来测试
        void ProcessConnection(std::shared_ptr<Socket> sock, InetAddr addr) {
            try{        
                std::string request_str;
                //throw std::length_error("尝试创建的字符串超出限制!!!");

                if(sock->Recv(&request_str, 4096)) {
                    std::string response = _handler(request_str);
                    sock->Send(response);
                    sock->CloseSocket();
                }
            } catch(const std::length_error& e) {
                ELOG("捕获到std::length_error异常：%s", e.what());
            }
        }

        void start() {
            _isrunning = true;
            
            while(_isrunning) {
                std::string clientip;
                uint16_t clientport;
                std::shared_ptr<Socket> sock = _listensock->AcceptConnection(&clientip, &clientport);
                if(sock == nullptr) 
                    continue;
                
                InetAddr addr(clientip, clientport);
                task_t task = std::bind(&TcpServer::ProcessConnection, this, sock, addr);
                ThreadPool<task_t>::getInstance()->push(task);
            }

            _isrunning = false;
        }
    private:
        uint16_t _port;
        std::unique_ptr<Socket> _listensock;
        bool _isrunning;
        handler_t _handler;
};
